package com.tabnet.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import com.tabnet.beans.commande.Commande;
import com.tabnet.beans.commande.LigneCommande;
import com.tabnet.beans.personnes.Client;
import com.tabnet.beans.produit.Etat;
import com.tabnet.dao.DAOCommande;
import com.tabnet.dao.DAOException;
import com.tabnet.dao.DAOFactory;
import com.tabnet.dao.DAOLigneCommande;
import com.tabnet.dao.DAOUtilitaire;

public class CommandeDAOImpl implements DAOCommande{
	
	private static final String SQL_SELECT_LAST		= "SELECT NUM_CMD FROM Commande ORDER BY NUM_CMD DESC LIMIT 0 , 1";
	private static final String SQL_SELECT_BY_NUM	= "SELECT NUM_CMD, ClientID, DateCMD, DateValidationCMD, Etat_Ref "
			+ "FROM Commande WHERE NUM_CMD=? AND ClientID=?";
	private static final String SQL_SELECT_ETAT		= "SELECT NUM_CMD, ClientID, DateCMD, DateValidationCMD, Etat_Ref "
			+ "FROM Commande WHERE ClientID=? AND Etat_Ref=?";
	private static final String SQL_INSERT			= "INSERT INTO Commande VALUES (?, ?, NOW(), ?, ?)";
	private static final String SQL_UPDATE_ETAT		= "UPDATE Commande SET DateValidationCMD=NOW(), Etat_Ref='ET_VAL' "
			+ "WHERE NUM_CMD=?";
	private static final String SQL_DELETE			= "DELETE FROM Commande WHERE NUM_CMD=? AND Etat_Ref='ET_ENC'";
	
	private final String ETAT_VALIDER = "ET_VAL";
	private final String ETAT_EN_COURS = "ET_ENC";
    
	private DAOFactory _DaoFactory;
	private DAOLigneCommande _DaoLigneCommande;
	
    public CommandeDAOImpl( DAOFactory pDaoFactory ) {
        this._DaoFactory = pDaoFactory;
        this._DaoLigneCommande = pDaoFactory.getLigneCommandeDAO();
    }

    /**
     * <p>Fonction map<br />
     * Simple méthode utilitaire permettant de faire la correspondance (le
     * mapping) entre une ligne issue de la table des commande (un ResultSet) et
     * un bean Commande.</p>
     * @param resultSet : objet ResultSet
     * @throws SQLException
     * @return un objet Commande
     * */
    private Commande map( ResultSet resultSet ) throws SQLException {
    	Commande oCommande = new Commande();
    	
    	oCommande.setNum(resultSet.getString("NUM_CMD"));
    	oCommande.setDateCommande(resultSet.getString("DateCMD"));
    	oCommande.setDateValidation(resultSet.getString("DateValidationCMD"));
    	
    	try {
	    		Client oClient = this._DaoFactory.getClientDAO().getClient(resultSet.getInt("ClientID"));
	    		oCommande.setClient(oClient);

	    		Etat oEtat = this._DaoFactory.getEtatDAO().trouverEtat(resultSet.getString("Etat_Ref"));
	    		oCommande.setEtat(oEtat);
	    		    	
    			// récupération des lignes commandes avec la DAO
    			Map<Integer, LigneCommande> mapLigneCommande = this._DaoLigneCommande.getLigneCommandes(oCommande);
    			oCommande.setLigneCommandes(mapLigneCommande);
        	
    		}
    		catch (DAOException e) {
    			e.printStackTrace();
    		}
    
        return oCommande;
    }
    
    /**
     * <p>Fonction getLastRef<br />
     * Retourne la dernière référence d'une commande</p>
     * @throws SQLException
     * @return la derniere reference de la base
     * */
    private String getLastRef() throws SQLException, DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet resultSet = null;
        
        String strRef = null;

        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
            // récupération des accessoires commandes
        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_SELECT_LAST, false);
            resultSet = oPreparedStatement.executeQuery();
            
            if ( resultSet.next() )
            	strRef = resultSet.getString("NUM_CMD");
        }
        catch ( SQLException e ) {
            throw new DAOException(e);
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses( resultSet, oPreparedStatement, oConnexion );
        }

        return strRef;
    }
    
    @Override
	public Commande getCommande(String pRef, int pIdClient) throws DAOException {
    	Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;
        
        Commande oCommande = null;
        
        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
            // récupération des commandes terminées
        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee(oConnexion, SQL_SELECT_BY_NUM, false, pRef, pIdClient);

        	oResultSet = oPreparedStatement.executeQuery();
        	
            if (oResultSet.next())
            	oCommande = map( oResultSet );
        }
        catch (SQLException e) {
            throw new DAOException(e);
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses(oResultSet, oPreparedStatement, oConnexion);
        }

        return oCommande;
	}
    
	@Override
	public Map<String, Commande> getCommandesTerminees(int pId) throws DAOException {
    	Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;
        
        Map<String, Commande> mapCommande = new HashMap<String, Commande>();
        Commande oCommande = null;
        
        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
            // récupération des commandes terminées
        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee(oConnexion, SQL_SELECT_ETAT, false, pId, this.ETAT_VALIDER);

        	oResultSet = oPreparedStatement.executeQuery();
        	
            while (oResultSet.next()) {
            	oCommande = map( oResultSet );
            	mapCommande.put(oCommande.getNum(), oCommande);
            }
        }
        catch (SQLException e) {
            throw new DAOException(e);
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses(oResultSet, oPreparedStatement, oConnexion);
        }

        return mapCommande;
	}

	@Override
	public Commande getCommandeEnCours(int pId) throws DAOException {
    	Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;
        
        Commande oCommande = null;
        
        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
            // récupération des commandes terminées
        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee(oConnexion, SQL_SELECT_ETAT, false, pId, this.ETAT_EN_COURS);

        	oResultSet = oPreparedStatement.executeQuery();
        	
            if(oResultSet.next())
            	oCommande = map(oResultSet);
        }
        catch (SQLException e) {
            throw new DAOException(e);
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses(oResultSet, oPreparedStatement, oConnexion);
        }

        return oCommande;
	}

	@Override
	public String addCommande(Client pClient) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;
		String strNewRef = null;
		
        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
        	//Récupération du dernier numéro de la commande
        	String strLastRef = this.getLastRef();
        	if(strLastRef == null)
        		strNewRef = "CMD_000001";
        	else if(strLastRef.length() == 10){
        		//Incrementation de cette derniere reference
        		String num = (Integer.parseInt(strLastRef.substring(5)) + 1) + ""; 
        		
        		while(num.length() < 6)
        			num = "0" + num;
        		
        		strNewRef = "CMD_" + num;
        	}
        	else
                throw new DAOException( "Échec de la récupération de la dernière référence." );
        	
            //insertion de la commande
            oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_INSERT, true,
            		strNewRef, pClient.getId(), null, this.ETAT_EN_COURS);
            
            if ( oPreparedStatement.executeUpdate() == 0 )
                throw new DAOException( "Échec de la création d'une commande, aucune ligne ajoutée dans la table." );
        	
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses(valeursAutoGenerees, oPreparedStatement, oConnexion);
        }
        
        return strNewRef;
	}

	@Override
	public void updCommande(String pRef) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;

        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
        	//mise a jour de la commande
        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee(oConnexion, SQL_UPDATE_ETAT, true, pRef);
        	
            if (oPreparedStatement.executeUpdate() == 0)
                throw new DAOException( "Échec de la mise a jour de la commande, aucune ligne modifiée dans la table." );

        }
        catch (SQLException e) {
            throw new DAOException(e);
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses(valeursAutoGenerees, oPreparedStatement, oConnexion);
        }
	}

	@Override
	public void delCommande(String pRef) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;
        
        try {
        	oConnexion = this._DaoFactory.getConnection();
            
            //suppression de la ligne de commande
        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee(oConnexion, SQL_DELETE, true, pRef);
        	            
            if (oPreparedStatement.executeUpdate() == 0)
                throw new DAOException( "Échec de la suppression de la commande, aucune ligne ajoutée dans la table." );

        }
        catch (SQLException e) {
            throw new DAOException(e);
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses(valeursAutoGenerees, oPreparedStatement, oConnexion);
        }
	}
}
